Skip to content

test+docs: harden and document the historical-import preserveAudit seam (#3493 follow-ups) - #3560

Merged
os-zhuang merged 1 commit into
mainfrom
claude/preserveaudit-symmetry
Jul 27, 2026
Merged

test+docs: harden and document the historical-import preserveAudit seam (#3493 follow-ups)#3560
os-zhuang merged 1 commit into
mainfrom
claude/preserveaudit-symmetry

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

背景

这是 #3493 / #3549 / #3556 的三项收尾(你说「按照我的建议继续完成所有」)。无行为改动——一条端到端测试 + 文档补全 + 一次对称性巡检结论。

1. 对称性巡检(结论:无需再修)

按建议先做了一次全仓巡检:排查是否还有其他「写回既有记录的历史快照」的路径遗漏了 preserveAudit(即 #3549 的同类缺陷)。

结论:导入撤销路由是唯一一条会写回业务记录「捕获快照 + 审计/业务 readonly 字段」的路径,而它已在 #3556 正确修复(按 treat_as_historical 条件带 preserveAudit)。其余近亲路径都不是同类缺陷:

  • 元数据版本回滚(restoreVersion / revertCommit / rollbackToPackageCommit):把旧的定义体写回 JSON 列,同时有意记一条全新的 operation_type='revert' append-only 事件——这里保留旧 updated_at 反而是错的,与 data import undo: 撤销一次「historical」导入无法还原被保留的 readonly / 审计字段 — undo 的 writeCtx 缺 preserveAudit (#3493 follow-up) #3549 的诉求相反。
  • 取消软删 / un-trash(权限集、附件/文件、API key):只是清 tombstone,合理地 stamp「现在」,并非快照回放。
  • seed 回放:带 isSystem/seedReplay 但不带 preserveAudit。因为 seed 是静态定义、没有「被捕获的真实时间线」,当前无缺陷;当 seed 语义将来改为携带权威历史时间戳时才需要补 preserveAudit——已在下方留档,不作为本 PR 的改动。

2. Real-SQLite 端到端测试(@objectstack/runtime)

packages/runtime/src/preserve-audit-real-driver.integration.test.ts——真实 ObjectQL 引擎 + 真实 SqlDriver(better-sqlite3,落盘),读回持久化行断言。

补上了 mock / 内存驱动结构上无法证明的那道缝:context.preserveAudit 穿过 buildDriverOptions 进入驱动 options,击穿真实 SQL 驱动对 updated_at 的强制 stamp。三条用例:

  1. 历史正向写:preserveAudit 保住 client 提供的 updated_at 与业务 readonly 字段 closed_at,一路写到磁盘。
  2. 普通写(对照):无 flag → 驱动强制 stamp updated_at(≠ 历史值),引擎 strip 掉 closed_at(从不落库)。
  3. 撤销 capstone(data import undo: 撤销一次「historical」导入无法还原被保留的 readonly / 审计字段 — undo 的 writeCtx 缺 preserveAudit (#3493 follow-up) #3549):带 preserveAudit 还原捕获快照 → updated_at 回滚到原值;不带 flag 的同样还原 → 被强制 stamp 成「现在」(正是 fix(rest): undo of a historical import preserves the audit timeline (#3549) #3556 修掉的破坏)。

mock/内存驱动只是回显 data.updated_at、从不强制 stamp,所以每一半单测(引擎审计 hook + strip 白名单对 mock;驱动 force-stamp 绕过对直接传入的 option)都测不到这道缝——只有真实驱动能。运行日志印证:对照用例打出 Field 'updated_at'/'closed_at' is read-only — ignoring incoming change (#2948)(被 strip),preserveAudit 用例无此警告(被保留)。

3. 文档补全

校验

  • check:docs ✅(253 生成文件 in sync)
  • check:api-surface ✅(describe 改动不影响 API surface)
  • check:doc-authoring ✅(213 文件 clean)
  • 新测试:Test Files 1 passed / Tests 3 passed

Changeset

空 frontmatter「releases nothing」——describe 字符串 + 重新生成的文档 + 一条新测试,无任何已发布包的行为改动。


🤖 Generated with Claude Code

https://claude.ai/code/session_01B5rdfBKjkbcoEif4KUV6xE


Generated by Claude Code

…am (#3493 follow-ups)

Follow-ups to #3493 / #3549 / #3556 — no behavior change.

Real-SQLite end-to-end test (@objectstack/runtime): wires the real ObjectQL
engine to the real SqlDriver (better-sqlite3) and proves the preserveAudit seam
that mock / in-memory drivers structurally cannot — that context.preserveAudit
threads through buildDriverOptions and defeats the SQL driver's updated_at
force-stamp on both the forward historical write and the undo restore, and that
a business readonly field (closed_at) survives the engine strip all the way to
disk. Includes the #3549 undo capstone: restore-under-preserveAudit rolls the
timeline back, while a plain restore re-stamps now (the bug #3556 fixed).

Docs: the treatAsHistorical schema describe (@objectstack/spec, regenerated
references/api/export.mdx) now documents all three effects — FSM skip (#3479),
audit-timeline preservation (#3493) and undo mirroring (#3556) — instead of only
the state-machine half; protocol/objectql/state-machine.mdx gains a bullet on
the symmetric undo behavior.

Also confirms (via a codebase audit) that the import-undo route was the only
business-record snapshot write-back path, so #3556 needs no sibling fix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B5rdfBKjkbcoEif4KUV6xE
@vercel

vercel Bot commented Jul 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 27, 2026 5:07am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/m labels Jul 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/runtime, @objectstack/spec.

111 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/api/wire-format.mdx (via @objectstack/runtime)
  • content/docs/automation/approvals.mdx (via packages/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via @objectstack/runtime, packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/runtime, packages/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/index.mdx (via @objectstack/runtime)
  • content/docs/deployment/production-readiness.mdx (via @objectstack/runtime)
  • content/docs/deployment/single-project-mode.mdx (via @objectstack/runtime)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/deployment/vercel.mdx (via @objectstack/runtime)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/permissions/authentication.mdx (via @objectstack/runtime)
  • content/docs/permissions/authorization.mdx (via packages/runtime, @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang marked this pull request as ready for review July 27, 2026 05:48
@os-zhuang
os-zhuang merged commit c80aece into main Jul 27, 2026
17 checks passed
@os-zhuang
os-zhuang deleted the claude/preserveaudit-symmetry branch July 27, 2026 05:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants